//
// Created by Yurzi on 2021/3/31.
//

#include "FileOperations.h"

//去格式化文件
void removeFormat(FILE *fp,char *filename){
    FILE *temp=fopen("temp","w+");   //创建传递文件
    char buff[1024]={0};    //初始化缓存

    //读取文件
    int i=0;char ctemp=0;
    int k=0;
    while (!feof(fp))
    {
        while (i<1024)
        {
            ctemp=fgetc(fp);
            if(ctemp==-1)break;
            if(ctemp!=' '&&ctemp!='\n'){
                buff[i]=ctemp;
                i++;
            }
        }

        //写出缓存
        while (k<i)
        {
            fputc(buff[k],temp);
            k++;
        }
        i=0;
        k=0;
    }
    fclose(fp);
    fclose(temp);
    remove(filename);
    rename("temp",filename);
    fp=fopen(filename,"r");
}

//读入一项材料
void mt_readOne(FILE *fp, Material *temp) {
    int count = 0;
    count = fscanf(fp, "\"%d\":{", &(temp->materialId));//读取id
    if (count <= 0) {
        free(temp);
        temp = NULL;
        return;
    }
    //printf("%d",temp->materialId);
    //读取name
    fscanf(fp, "\"mtName\":");
    int i = 0;
    bool flag = true;
    char ctemp = fgetc(fp);//读取”
    while (i < (MAX_NAMELENGTH_KTM - 1)) {
        ctemp = fgetc(fp);
        if (ctemp == '\"') {
            flag = false;
            break;
        }
        temp->materialName[i] = ctemp;
        i++;
    }
    temp->materialName[i] = 0;//加上结尾
    if (flag)fgetc(fp);//消除可能未消除的“
    //printf("%s",temp->materialName);
    fgetc(fp);//读取，
    //读取后续内容
    fscanf(fp, "\"mtPrice\":%lf,\"mtAmount\":%d}", &(temp->price), &(temp->amount));
}

//读入一项类
void kind_readOne(FILE *fp,Kind *temp){
    int count=0;
    count=fscanf(fp,"\"%d\":{",&temp->kindId); //读取kindId
    if(count<=0){free(temp);temp=NULL;return;}

    //读取name
    fscanf(fp,"\"kindName\":");
    int i=0;
    bool flag=true;
    char ctemp=fgetc(fp);//读取"
    while(i<(MAX_NAMELENGTH_KTM-1)){
        ctemp=fgetc(fp);
        if (ctemp=='\"'){flag=false;break;}
        temp->kindName[i]=ctemp;
        i++;
    }
    temp->kindName[i]=0;//加上结尾
    if(flag)fgetc(fp);//读取可能的"
    fgetc(fp);//读取}

}

//读入标签里的一个原料
int tag_readOneMt(FILE *fp,Material *mt){
    char ctemp=fgetc(fp);
    if (ctemp!='{')
    {
        fseek(fp,-1,SEEK_CUR);//退回上一格
        return -1;  //若没原料则返回-1代表错误
    }

    //若合法
    //读入原料id
    fscanf(fp,"\"mtId\":%d,",&(mt->materialId));
    //printf("%d\n",mt->materialId);

    //读取原料名称
    fscanf(fp,"\"mtName\":");
    int i=0;
    bool flag=true;
    ctemp=fgetc(fp);   //读取"
    while (i<MAX_NAMELENGTH_KTM-1)
    {
        ctemp=fgetc(fp);
        if(ctemp=='\"'){flag=false;break;}
        mt->materialName[i]=ctemp;
        i++;
    }
    mt->materialName[i]=0; //加上结尾的0
    if(flag)fgetc(fp);  //消除可能存在的"
    fgetc(fp);//读取,

    //读取原料价格
    fscanf(fp,"\"mtPrice\":%lf,",&(mt->price));

    //读取原料消耗数量
    fscanf(fp,"\"mtAmount\":%d}",&(mt->amount));

    ctemp=fgetc(fp);
    if (ctemp!=',')
    {
        fseek(fp,-1,SEEK_CUR);//退回上一格
    }

    return 0;
}

//读入一个标签
void tag_readOne(FILE *fp,Tag *temp){
    int count=0;
    count=fscanf(fp,"\"%d\":{",&(temp->tagId));   //读入便签id
    if(count<1){free(temp);temp=NULL;return;}    //判断文件是否合法

    //读入标签名字
    fscanf(fp,"\"tagName\":");
    int i=0;
    bool flag=true;
    char ctemp=fgetc(fp);   //读取"
    while (i<MAX_NAMELENGTH_KTM-1)
    {
        ctemp=fgetc(fp);
        if(ctemp=='\"'){flag=false;break;}
        temp->tagName[i]=ctemp;
        i++;
    }
    temp->tagName[i]=0; //加上结尾的0
    if(flag)fgetc(fp);  //消除可能存在的"
    fgetc(fp);//读取,

    //读取价格
    fscanf(fp,"\"price\":%lf,",&(temp->price));

    //读取原料
    fscanf(fp,"\"materials\":[");
    int k=0;
    while (k<MAX_LABELSIZE)
    {
        if(tag_readOneMt(fp,&(temp->materials[k]))==-1){
            temp->materials[k].materialId=-1;
            break;
        }
        ++k;
    }
    fgetc(fp);  //读取]
    fgetc(fp);  //读取}
}

//读入一个商品里的原料
int good_readOneMt(FILE *fp,Material *mt){
    char ctemp=fgetc(fp);
    if (ctemp!='{')
    {
        fseek(fp,-1,SEEK_CUR);//退回上一格
        return -1;  //若没原料则返回-1代表错误
    }

    //若合法
    //读入原料id
    fscanf(fp,"\"mtId\":%d,",&(mt->materialId));
    //printf("%d\n",mt->materialId);

    //读取原料名称
    fscanf(fp,"\"mtName\":");
    int i=0;
    bool flag=true;
    ctemp=fgetc(fp);   //读取"
    while (i<MAX_NAMELENGTH_KTM-1)
    {
        ctemp=fgetc(fp);
        if(ctemp=='\"'){flag=false;break;}
        mt->materialName[i]=ctemp;
        i++;
    }
    mt->materialName[i]=0; //加上结尾的0
    if(flag)fgetc(fp);  //消除可能存在的"
    fgetc(fp);//读取,

    //读取原料价格
    fscanf(fp,"\"mtPrice\":%lf,",&(mt->price));

    //读取原料消耗数量
    fscanf(fp,"\"mtAmount\":%d}",&(mt->amount));

    ctemp=fgetc(fp);
    if (ctemp!=',')
    {
        fseek(fp,-1,SEEK_CUR);//退回上一格
    }

    return 0;
}

//读入一个商品的标签
int good_readOneTag(FILE *fp,Tag *temp){
    char ctemp=fgetc(fp);
    if (ctemp!='{')
    {
        fseek(fp,-1,SEEK_CUR);//退回上一格
        return -1;  //若没便签则返回-1代表错误
    }
    //读入标签id
    fscanf(fp,"\"tagId\":%d,",&(temp->tagId));

    //读入标签名字
    fscanf(fp,"\"tagName\":");
    int i=0;
    bool flag=true;
    ctemp=fgetc(fp);   //读取"
    while (i<MAX_NAMELENGTH_KTM-1)
    {
        ctemp=fgetc(fp);
        if(ctemp=='\"'){flag=false;break;}
        temp->tagName[i]=ctemp;
        i++;
    }
    temp->tagName[i]=0; //加上结尾的0
    if(flag)fgetc(fp);  //消除可能存在的"
    fgetc(fp);//读取,

    //读取价格
    fscanf(fp,"\"price\":%lf,",&(temp->price));

    //读取原料
    fscanf(fp,"\"materials\":[");
    int k=0;
    while (k<MAX_LABELSIZE)
    {
        if(-1==tag_readOneMt(fp,&(temp->materials[k]))){
            temp->materials[k].materialId=-1;
            break;
        }
        ++k;
    }
    fgetc(fp);  //读取]
    fgetc(fp);  //读取}

    ctemp=fgetc(fp);
    if (ctemp!=',')
    {
        fseek(fp,-1,SEEK_CUR);//退回上一格
    }

    return 0;
}

//读入一个商品
void good_readOne(FILE *fp,Good *temp){
    int int2bool=0; //用于将整形转化为布尔值
    int count=0;
    count=fscanf(fp,"\"%d\":{",&(temp->goodId));   //读入商品id
    if(count<1){free(temp);temp=NULL;return;}    //判断文件是否合法

    //读取商品类id
    fscanf(fp,"\"kindId\":%d,",&(temp->kindId));

    //读取商品名字
    fscanf(fp,"\"goodName\":");
    int i=0;
    bool flag=true;
    char ctemp=fgetc(fp);   //读取"
    while (i<MAX_NAMELENGTH_G-1){
        ctemp=fgetc(fp);
        if(ctemp=='\"'){flag=false;break;}
        temp->goodName[i]=ctemp;
        i++;
    }
    temp->goodName[i]=0; //加上结尾的0
    if(flag)fgetc(fp);  //消除可能存在的"
    fgetc(fp);//读取,

    //读取商品的价格
    fscanf(fp,"\"price\":%lf,",&(temp->price));

    //读取商品可热/冷
    fscanf(fp,"\"canIce\":%d,",&int2bool);
    if(int2bool){temp->ice=true;}else{temp->ice=false;}
    fscanf(fp,"\"canHot\":%d,",&int2bool);
    if(int2bool){temp->hot=true;}else{temp->hot=false;}

    //读取商品能否支持大杯超大杯
    fscanf(fp,"\"canBig\":%lf,",&(temp->big));
    fscanf(fp,"\"canSBig\":%lf,",&(temp->sbig));

    //读取商品标签
    fscanf(fp,"\"tags\":[");
    int k=0;
    while (k<MAX_LABELSIZE)
    {
        if(-1==good_readOneTag(fp,&(temp->tags[k]))){
            temp->tags[k].tagId=-1;
            break;
        }
        ++k;
    }
    ctemp=fgetc(fp);  //读取]
    ctemp=fgetc(fp);  //读取，
    //读取商品原料
    fscanf(fp,"\"materials\":[");
    k=0;
    while (k<MAX_LABELSIZE)
    {
        if(-1==good_readOneMt(fp,&(temp->materials[k]))){
            temp->materials[k].materialId=-1;
            break;
        }
        ++k;
    }
    ctemp=fgetc(fp);  //读取]
    ctemp=fgetc(fp); //读取}
}

//往文件中写入一个类
void kind_writeOne(FILE *fp,Kind *temp){
    //写入类id以及符号:{
    fprintf(fp,"\"%d\":{",temp->kindId);

    //写入类名称及符号}
    fprintf(fp,"\"kindName\":\"%s\"}",temp->kindName);
}

//往文件中写入类链表
int save_kindList(FILE *kindFilePtr,Kind *kindList){
    if(kindList==NULL||kindFilePtr==NULL)return -1;
    //写入最外层{
    fprintf(kindFilePtr,"{");
    Kind *p=kindList;
    while (p!=NULL)
    {
        //写入一个类对象
        kind_writeOne(kindFilePtr,p);
        //写入类对象间,
        if(p->next!=NULL){fprintf(kindFilePtr,",");}
        //指针游走
        p=p->next;
    }
    //写入最外层}
    fprintf(kindFilePtr,"}");
    return 0;
}

//往文件中写入一个原料
void mt_writeOne(FILE *fp,Material *temp){
    //写入原料id以及符号:{
    fprintf(fp,"\"%d\":{",temp->materialId);

    //写入原料名称及,
    fprintf(fp,"\"mtName\":\"%s\",",temp->materialName);

    //写入原料的价格及,
    fprintf(fp,"\"mtPrice\":%lf,",temp->price);

    //写入原料的数量及}
    fprintf(fp,"\"mtAmount\":%d}",temp->amount);
}

//往文件中写入原料链表
int save_mtList(FILE *mtFilePtr,Material *mtList){
    if(mtList==NULL||mtFilePtr==NULL)return -1;
    //写入最外层{
    fprintf(mtFilePtr,"{");
    Material *p=mtList;
    while (p!=NULL)
    {
        //写入一个原料对象
        mt_writeOne(mtFilePtr,p);
        //写入原料对象间,
        if(p->next!=NULL){fprintf(mtFilePtr,",");}
        //指针游走
        p=p->next;
    }
    //写入最外层}
    fprintf(mtFilePtr,"}");
    return 0;
}

//往文件中写入一个标签的原料对象
void tag_writeOneMt(FILE *fp,Material *temp){
    //输入{
    fprintf(fp,"{");

    //写入原料id及,
    fprintf(fp,"\"mtId\":%d,",temp->materialId);

    //写入原料名称及,
    fprintf(fp,"\"mtName\":\"%s\",",temp->materialName);

    //写入原料的价格及,
    fprintf(fp,"\"mtPrice\":%lf,",temp->price);

    //写入原料的数量
    fprintf(fp,"\"mtAmount\":%d",temp->amount);

    //输入}
    fprintf(fp,"}");
}

//往文件中写入一个标签
void tag_writeOne(FILE *fp,Tag *temp){
    //写入标签id以及符号:{
    fprintf(fp,"\"%d\":{",temp->tagId);

    //写入标签名称及,
    fprintf(fp,"\"tagName\":\"%s\",",temp->tagName);

    //写入标签的价格及,
    fprintf(fp,"\"price\":%lf,",temp->price);

    //写入标签的原料
    //写入键名及:[
    fprintf(fp,"\"materials\":[");
    //写入原料对象
    int i=0;
    while (i<MAX_LABELSIZE&&((temp->materials[i].materialId>0)))
    {
        //写入一个对象
        tag_writeOneMt(fp,&(temp->materials[i]));
        //输入对象间隔的,
        if((i<MAX_LABELSIZE-1)&&(temp->materials[i+1].materialId>0)){
            fprintf(fp,",");
        }
        ++i;
    }
    //写入标签原料结尾的]
    fprintf(fp,"]");
    //写入标签对象结尾的}
    fprintf(fp,"}");
}

//往文件中写入标签链表
int save_tagList(FILE *tagFilePtr,Tag *tagList){
    if(tagList==NULL||tagFilePtr==NULL)return -1;
    //写入最外层{
    fprintf(tagFilePtr,"{");
    Tag *p=tagList;
    while (p!=NULL)
    {
        //写入一个标签对象
        tag_writeOne(tagFilePtr,p);
        //写入标签对象间,
        if(p->next!=NULL){fprintf(tagFilePtr,",");}
        //指针游走
        p=p->next;
    }
    //写入最外层}
    fprintf(tagFilePtr,"}");
    return 0;
}

//往文件中写入一个商品的原料对象
void good_writeOneMt(FILE *fp,Material *temp){
    //输入{
    fprintf(fp,"{");

    //写入原料id及,
    fprintf(fp,"\"mtId\":%d,",temp->materialId);

    //写入原料名称及,
    fprintf(fp,"\"mtName\":\"%s\",",temp->materialName);

    //写入原料的价格及,
    fprintf(fp,"\"mtPrice\":%lf,",temp->price);

    //写入原料的数量
    fprintf(fp,"\"mtAmount\":%d",temp->amount);

    //输入}
    fprintf(fp,"}");
}

//往文件中写入商品中的一个标签
void good_writeOneTag(FILE *fp,Tag *temp){
    //写入标签对象的起始{
    fprintf(fp,"{");

    //写入标签的id及,
    fprintf(fp,"\"tagId\":%d,",temp->tagId);

    //写入标签名称及,
    fprintf(fp,"\"tagName\":\"%s\",",temp->tagName);

    //写入标签的价格及,
    fprintf(fp,"\"price\":%lf,",temp->price);

    //写入标签的原料
    //写入键名及:[
    fprintf(fp,"\"materials\":[");
    //写入原料对象
    int i=0;
    while (i<MAX_LABELSIZE&&((temp->materials[i].materialId>0)))
    {
        //写入一个对象
        tag_writeOneMt(fp,&(temp->materials[i]));
        //输入对象间隔的,
        if((i<MAX_LABELSIZE-1)&&(temp->materials[i+1].materialId>0)){
            fprintf(fp,",");
        }
        ++i;
    }
    //写入标签原料结尾的]
    fprintf(fp,"]");
    //写入标签对象结尾的}
    fprintf(fp,"}");


}

//往文件中写入一个商品
void good_writeOne(FILE *fp,Good *temp){
    //写入商品id以及符号:{
    fprintf(fp,"\"%d\":{",temp->goodId);

    //写入商品的类id及,
    fprintf(fp,"\"kindId\":%d,",temp->kindId);

    //写入商品名称及,
    fprintf(fp,"\"goodName\":\"%s\",",temp->goodName);

    //写入商品的价格及,
    fprintf(fp,"\"price\":%lf,",temp->price);

    //写入商品的冷/热属性
    if (temp->ice)
    {
        fprintf(fp,"\"canIce\":%d,",1);
    }else{
        fprintf(fp,"\"canIce\":%d,",0);
    }
    if (temp->hot)
    {
        fprintf(fp,"\"canHot\":%d,",1);
    }else{
        fprintf(fp,"\"canHot\":%d,",0);
    }
    //写入商品是否支持大杯超大杯
    fprintf(fp,"\"canBig\":%lf,",temp->big);
    fprintf(fp,"\"canSBig\":%lf,",temp->sbig);


    //写入商品的标签
    //写入键名及:[
    fprintf(fp,"\"tags\":[");
    //写入标签对象
    int i=0;
    while (i<MAX_LABELSIZE&&((temp->tags[i].tagId)>0))
    {
        //写入一个标签对象
        good_writeOneTag(fp,&(temp->tags[i]));
        //输入对象间的,
        if((i<MAX_LABELSIZE-1)&&((temp->tags[i+1].tagId)>0)){
            fprintf(fp,",");
        }
        ++i;
    }
    //写入标签结束的],
    fprintf(fp,"],");


    //写入商品原料
    //写入键名及:[
    fprintf(fp,"\"materials\":[");
    i=0;
    while (i<MAX_LABELSIZE&&((temp->materials[i].materialId)>0))
    {
        //写入一个原料对象
        good_writeOneMt(fp,&(temp->materials[i]));
        //输入对象间的,
        if((i<MAX_LABELSIZE-1)&&((temp->materials[i+1].materialId)>0)){
            fprintf(fp,",");
        }
        ++i;
    }
    //写入原料结束的]
    fprintf(fp,"]");
    //写入商品对象的}
    fprintf(fp,"}");
}

//往文件中写入商品链表
int save_goodList(FILE *goodFilePtr,Good *goodList){
    if(goodList==NULL||goodFilePtr==NULL)return -1;
    //写入最外层{
    fprintf(goodFilePtr,"{");
    Good *p=goodList;
    while (p!=NULL)
    {
        //写入一个商品对象
        good_writeOne(goodFilePtr,p);
        //写入商品对象间,
        if(p->next!=NULL){fprintf(goodFilePtr,",");}
        //指针游走
        p=p->next;
    }
    //写入最外层}
    fprintf(goodFilePtr,"}");
    return 0;
}
//在文件中读入历史记录链表
int read_logList(FILE *logFilePtr,LogNode** _logList_head,LogNode** _logList_rear){
    LogNode *head= malloc(sizeof(LogNode));
    LogNode *p=head;
    LogNode *p0=head;

    if(fread(p,sizeof(LogNode),1,logFilePtr)==0){
        free(p);
        return _ERROR;
    }
    head->next=NULL;head->prv=NULL;
    *_logList_head=head;
    while (!feof(logFilePtr)){
        p=malloc(sizeof(LogNode));
        if(fread(p,sizeof(LogNode),1,logFilePtr)==0){
            free(p);
            *_logList_rear=p0;
            return -2;
        }
        p->next=NULL;p->prv=NULL;
        p0->next=p;
        p->prv=p0;
        p0=p;
    }
    *_logList_rear=p0;
    return ALLISOK;
}



//在文件中写入历史记录链表
int save_logList(FILE *logFilePtr,LogNode *_logList){
    if(_logList==NULL||logFilePtr==NULL){
        return _ERROR;
    }
    LogNode *p=_logList;
    while (p!=NULL){
        //写入一条历史记录
        fwrite(p,sizeof(LogNode),1,logFilePtr);
        p=p->next;
    }
    return ALLISOK;
}